35. 使用JTA处理分布式事务

Spring Boot通过AtomkosBitronix的内嵌事务管理器支持跨多个XA资源的分布式JTA事务,当部署到恰当的J2EE应用服务器时也会支持JTA事务。

当发现JTA环境时,Spring Boot将使用Spring的JtaTransactionManager来管理事务。自动配置的JMS,DataSource和JPA beans将被升级以支持XA事务。你可以使用标准的Spring idioms,比如@Transactional,来参与到一个分布式事务中。如果处于JTA环境,但仍想使用本地事务,你可以将spring.jta.enabled属性设置为false来禁用JTA自动配置功能。

35.1 使用Atomikos事务管理器

Atomikos是一个非常流行的开源事务管理器,并且可以嵌入到你的Spring Boot应用中。你可以使用spring-boot-starter-jta-atomikosStarter去获取正确的Atomikos库。Spring Boot会自动配置Atomikos,并将合适的depends-on应用到你的Spring Beans上,确保它们以正确的顺序启动和关闭。

默认情况下,Atomikos事务日志将被记录在应用home目录(你的应用jar文件放置的目录)下的transaction-logs文件夹中。你可以在application.properties文件中通过设置spring.jta.log-dir属性来定义该目录,以spring.jta.atomikos.properties开头的属性能用来定义Atomikos的UserTransactionServiceIml实现,具体参考AtomikosProperties javadoc

为了确保多个事务管理器能够安全地和相应的资源管理器配合,每个Atomikos实例必须设置一个唯一的ID。默认情况下,该ID是Atomikos实例运行的机器上的IP地址。为了确保生产环境中该ID的唯一性,你需要为应用的每个实例设置不同的spring.jta.transaction-manager-id属性值。

35.2 使用Bitronix事务管理器

Bitronix是一个流行的开源JTA事务管理器实现,你可以使用spring-boot-starter-jta-bitronixstarter为项目添加合适的Birtronix依赖。和Atomikos类似,Spring Boot将自动配置Bitronix,并对beans进行后处理(post-process)以确保它们以正确的顺序启动和关闭。

默认情况下,Bitronix事务日志(part1.btmpart2.btm)将被记录到应用home目录下的transaction-logs文件夹中,你可以通过设置spring.jta.log-dir属性来自定义该目录。以spring.jta.bitronix.properties开头的属性将被绑定到bitronix.tm.Configuration bean,你可以通过这完成进一步的自定义,具体参考Bitronix文档

为了确保多个事务管理器能够安全地和相应的资源管理器配合,每个Bitronix实例必须设置一个唯一的ID。默认情况下,该ID是Bitronix实例运行的机器上的IP地址。为了确保生产环境中该ID的唯一性,你需要为应用的每个实例设置不同的spring.jta.transaction-manager-id属性值。

35.3 使用Narayana事务管理器

Narayana是一个流行的开源JTA事务管理器实现,目前只有JBoss支持。你可以使用spring-boot-starter-jta-narayana starter添加合适的Narayana依赖,像Atomikos和Bitronix那样,Spring Boot将自动配置Narayana,并对你的beans后处理(post-process)以确保正确启动和关闭。

Narayana事务日志默认记录到应用home目录(放置应用jar的目录)的transaction-logs目录下,你可以通过设置application.properties中的spring.jta.log-dir属性自定义该目录。以spring.jta.narayana.properties开头的属性可用于自定义Narayana配置,具体参考NarayanaProperties

为了确保多事务管理器能够安全配合相应资源管理器,每个Narayana实例必须配置唯一的ID,默认ID设为1。为确保生产环境中ID唯一性,你可以为应用的每个实例配置不同的spring.jta.transaction-manager-id属性值。

35.4 使用J2EE管理的事务管理器

如果你将Spring Boot应用打包为一个warear文件,并将它部署到一个J2EE的应用服务器中,那你就能使用应用服务器内建的事务管理器。Spring Boot将尝试通过查找常见的JNDI路径(java:comp/UserTransaction, java:comp/TransactionManager等)来自动配置一个事务管理器。如果使用应用服务器提供的事务服务,你通常需要确保所有的资源都被应用服务器管理,并通过JNDI暴露出去。Spring Boot通过查找JNDI路径java:/JmsXAjava:/XAConnectionFactory获取一个ConnectionFactory来自动配置JMS,并且你可以使用spring.datasource.jndi-name属性配置你的DataSource

35.5 混合XA和non-XA的JMS连接

当使用JTA时,primary JMS ConnectionFactorybean将能识别XA,并参与到分布式事务中。有些情况下,你可能需要使用non-XA的ConnectionFactory去处理一些JMS消息。例如,你的JMS处理逻辑可能比XA超时时间长。

如果想使用一个non-XA的ConnectionFactory,你可以注入nonXaJmsConnectionFactory bean而不是@Primary jmsConnectionFactory bean。为了保持一致,jmsConnectionFactory bean将以别名xaJmsConnectionFactor来被使用。

示例如下:

// Inject the primary (XA aware) ConnectionFactory
@Autowired
private ConnectionFactory defaultConnectionFactory;
// Inject the XA aware ConnectionFactory (uses the alias and injects the same as above)
@Autowired
@Qualifier("xaJmsConnectionFactory")
private ConnectionFactory xaConnectionFactory;
// Inject the non-XA aware ConnectionFactory
@Autowired
@Qualifier("nonXaJmsConnectionFactory")
private ConnectionFactory nonXaConnectionFactory;

35.6 支持可替代的内嵌事务管理器

XAConnectionFactoryWrapperXADataSourceWrapper接口用于支持可替换的内嵌事务管理器。该接口用于包装XAConnectionFactoryXADataSource beans,并将它们暴露为普通的ConnectionFactoryDataSource beans,这样在分布式事务中可以透明使用。Spring Boot将使用注册到ApplicationContext的合适的XA包装器及JtaTransactionManager bean自动配置你的DataSource和JMS。

BitronixXAConnectionFactoryWrapperBitronixXADataSourceWrapper提供很好的示例用于演示怎么编写XA包装器。